
use std::convert::Infallible;

use headers::{authorization::Basic, Authorization, HeaderMapExt};
use dav_server::{body::Body, localfs::LocalFs, memls::MemLs, DavConfig, DavHandler};
use wtask_base::{export::log_debug, machine::{get_home_dir, get_machine_token}};

#[derive(Clone)]
pub struct WebDAVServer {
    dh: DavHandler,
}

impl Default for WebDAVServer {
    fn default() -> Self {
        let config = DavHandler::builder()
        .filesystem(LocalFs::new(get_home_dir(), false, false, false))
        .locksystem(MemLs::new());

        Self {
            dh: config.build_handler()
        }
    }
}

impl WebDAVServer {
    pub async fn handle(
        &self,
        req: hyper::Request<hyper::body::Incoming>,
    ) -> Result<hyper::Response<Body>, Infallible> {
        let user = {
            let machine_token = get_machine_token().unwrap();
            match req.headers().typed_get::<Authorization<Basic>>() {
                Some(Authorization(basic)) if basic.password().eq(&machine_token) => Some(basic.username().to_string()),
                _ => {
                    log_debug!("auth error: {:?}", req.headers());
                    let response = hyper::Response::builder()
                        .status(401)
                        .header("WWW-Authenticate", "Basic realm=\"wTask\"")
                        .body(Body::from("please auth".to_string()))
                        .unwrap();
                    return Ok(response);
                }
            }
        };

        if let Some(user) = user {
            let config = DavConfig::new().principal(user);
            Ok(self.dh.handle_with(config, req).await)
        } else {
            Ok(self.dh.handle(req).await)
        }
    }
}
